class Person {
    String name
    String motto
    String salt
    String password
    String passwordConfirmation
    SortedSet widgets
    Integer widgetCount = 0

    Date dateCreated = new Date()
    Date lastUpdated = new Date()
    
    static hasMany = [ widgets: Widget ]


    static transients = [ 'passwordConfirmation' ]

    static constraints = {
        name(size: 1..40, blank: false, unique: true)
        motto(size: 0..80, nullable: true)
        password(maxSize: 40, nullable: false, validator: Person.validatePassword)
        salt(maxSize: 40, blank: false, nullable: false)
    }

    static mapping = {
        widgets cascade: 'all-delete-orphan', lazy: true, inverse: true
        name index: 'persons_name_index', unique: true
    }

    String toString() {
        "${name}"
    }
      
    static Person authenticate(String name, String password) {
        Person person = Person.findByName(name)
        if (person) {
            if (person.password != encryptedPassword(person.salt, password)) {
                person = null
            }
        }
        person
    }

    private static validatePassword = { password, person ->
        if (!person.id) {
            person.salt = "--${System.currentTimeMillis().toString()}--${Math.random().toString()}--".encodeAsPassword()
            password = password?.trim()
            if (!password) {
                password = ""
            }
            if (password.length() < 6 || password.length() > 40) {
                person.errors.rejectValue('password', 'person.password.length',
                    ['password', 'Person', password] as Object[], 
                    'Property [{0}] of class [{1}] must be between 6 and 40 characters')
            }
            else {
                person.password = encryptedPassword(person.salt, password)
            }
        }
        true
    }
    
    private static String encryptedPassword(salt, password) {
        "--${salt}--${password}--".encodeAsPassword()
    }
}
